#ifndef _COMPILATION_PHI_FRONTIER_TASK_H_
#define _COMPILATION_PHI_FRONTIER_TASK_H_

#include <compilation/Forward.h>

#include <vector>
#include <map>
#include <set>

#include <compilation/task/Task.h>
#include <compilation/task/Handler.h>
#include <compilation/task/Propagator.h>
#include <compilation/task/Phi.h>

#include <compilation/instruction/Expression.h>
#include <compilation/instruction/ExpressionVisitor.h>

#include <compilation/instruction/Instruction.h>
#include <compilation/instruction/InstructionVisitor.h>


// LabelPhiFrontierTask and LabelPhiFrontierAgenda.
namespace compilation
{

class LabelPhiFrontierTask
    : public VirtualTask
{
public:

  typedef PhiIsBefore IsBefore;

  typedef PhiLabelResult::ModifiedVariables ModifiedVariables;

  ModifiedVariables m_modified;

public:

  LabelPhiFrontierTask(
      const LabelInstruction& label,
      ModifiedVariables& modified)
  { setInstruction(label); m_modified.swap(modified); }

  LabelPhiFrontierTask(const LabelPhiFrontierTask& source)
    : VirtualTask(source) {}

  ModifiedVariables& getModifiedVariables(void)
  { return m_modified; }

  ModifiedVariables const& getModifiedVariables(void) const
  { return m_modified; }

  virtual VirtualTask* clone(void) const
  { return new LabelPhiFrontierTask(*this); }

};

class LabelPhiFrontierAgenda
    : public VirtualAgenda
{
public:

  typedef LabelPhiFrontierTask Task;

  typedef PhiLabelResult::ModifiedVariables ModifiedVariables;

  typedef PhiIsBefore IsBefore;

  typedef PhiLabelResult LabelResult;

  typedef InstructionVisitor<
  void, LabelPhiFrontierTask&, LabelPhiFrontierAgenda&, WorkListReusability&>
  instruction_handler_visitor_type;

  typedef InstructionVisitor<
  bool, LabelPhiFrontierTask&, LabelPhiFrontierAgenda&, WorkListReusability&>
  instruction_propagator_visitor_type;

  instruction_handler_visitor_type const& handleInstruction;

  instruction_propagator_visitor_type const& propagateOnUnmarked;

  LabelPhiFrontierAgenda(
      instruction_handler_visitor_type const& instruction_handler_visitor,
      instruction_propagator_visitor_type const& instruction_propagator_visitor)
    : handleInstruction(instruction_handler_visitor)
    , propagateOnUnmarked(instruction_propagator_visitor) {}

  void propagate(LabelInstruction &label);

  void propagateOn(
      const LabelInstruction& label,
      ModifiedVariables const& originModified);

  void markInstructionWith(VirtualInstruction &instruction, VirtualTask &task) {}
};

} // compilation

// LabelPhiFrontierInstructionHandler.
namespace compilation
{

template <InstructionType _Type>
struct LabelPhiFrontierInstructionHandler
    : public InstructionHandler<_Type, LabelPhiFrontierTask, LabelPhiFrontierAgenda>
{
  void operator ()(
      VirtualInstruction* instr,
      LabelPhiFrontierTask& task,
      LabelPhiFrontierAgenda& continuations,
      WorkListReusability& reuse)
  {
    InstructionHandler<_Type, LabelPhiFrontierTask, LabelPhiFrontierAgenda>
        ::operator ()(instr,task,continuations,reuse);
  }
};

template <>
struct LabelPhiFrontierInstructionHandler<TLabel>
    : public InstructionHandler<TLabel, LabelPhiFrontierTask, LabelPhiFrontierAgenda>
{
  void operator ()(
      VirtualInstruction* instr,
      LabelPhiFrontierTask& task,
      LabelPhiFrontierAgenda& continuations,
      WorkListReusability& reuse);
};

} // compilation

#endif // _COMPILATION_PHI_FRONTIER_TASK_H_
